package net.koodar.forge.security;

import net.koodar.forge.security.config.SecurityConfigurer;
import net.koodar.forge.security.domain.properties.SecurityProperties;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;

import java.util.List;

import static org.springframework.security.config.Customizer.withDefaults;

/**
 * AutoConfiguration
 *
 * @author liyc
 */
@Configuration
public class SecurityAutoConfiguration {

	private final SecurityProperties.Initializer initializer;

	private final ObjectProvider<SecurityConfigurer> securityConfigurers;

	private final List<String> ignoreUrlList;


	public SecurityAutoConfiguration(ObjectProvider<SecurityConfigurer> securityConfigurers, List<String> ignoreUrlList) {
		this.ignoreUrlList = ignoreUrlList;
		this.initializer = new SecurityProperties.Initializer();
		this.securityConfigurers = securityConfigurers;
	}

	@Bean
	public PasswordEncoder passwordEncoder() {
		return new BCryptPasswordEncoder();
	}

	@Bean
	public AuthenticationProvider authenticationProvider(UserDetailsService userDetailsService,
														 PasswordEncoder passwordEncoder) {
		DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
		provider.setUserDetailsService(userDetailsService);
		provider.setPasswordEncoder(passwordEncoder);
		return provider;
	}

	/**
	 * 忽略的url集合
	 */
	protected String[] getIgnoreUrlList() {
		return ignoreUrlList.toArray(new String[0]);
	}

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

		// 不开启session会话模式
		http.sessionManagement((authorize) -> authorize.sessionCreationPolicy(SessionCreationPolicy.STATELESS));

		// 是否禁用csrf
		if(initializer.isDisableCsrf()) {
			http.csrf(AbstractHttpConfigurer::disable);
		}

		http
				.authorizeHttpRequests((authorize) -> authorize
						// 忽略OPTIONS请求
						.requestMatchers(HttpMethod.OPTIONS, "/**").permitAll()
						// 忽略的url
						.requestMatchers(this.getIgnoreUrlList()).permitAll()
						// 需要校验权限的url
						.requestMatchers("/**").authenticated()
				)
				.formLogin(withDefaults())
				.logout(withDefaults());

		// 与其他 Configurer 集成
		securityConfigurers.orderedStream()
				.forEach(securityConfigurer -> securityConfigurer.configure(http));

		return http.build();
	}



}
